import celery
import json
import pagure
import rdflib

from .. import activitypub
from .. import model
from .. import settings

from . import broker
from . import broker_url
from . import database_session

log = celery.utils.log.get_task_logger(__name__)
log.setLevel(settings.LOG_LEVEL)

@broker.task
def handle_pagure_signal(topic, message):
    """
    This task receives notifications from Pagure about events that happen on
    the instance, creates a new activity, and schedules their delivery.
    """
    
    log.debug('New notification from Pagure: ' + topic)
    log.debug(json.dumps(message, indent=4, sort_keys=True))
    
    with database_session() as (pagure_db, forgefed_db):
        
        if topic == 'issue.new':
            # A user has created a new issue
            
            person = pagure_db \
                        .query(model.Person) \
                        .filter(model.Person.user == message['issue']['user']['name']) \
                        .one_or_none()
            
            project = pagure_db \
                .query(model.Projects) \
                .filter(model.Projects.id == message['project']['id']) \
                .one_or_none()
            
            issue = pagure_db \
                .query(pagure.lib.model.Issue) \
                .filter(pagure.lib.model.Issue.id == message['issue']['id'],
                        pagure.lib.model.Issue.project_id == message['project']['id']) \
                .one_or_none()
            
            # This should never raise an error otherwise there's a bug in Pagure
            assert person and issue and project, \
                   'User or or project doesn\'t exist.'
            
            # Check if this tracker is only used to interact with a remote one
            same_as = forgefed_db.query(database.SameAs) \
                              .filter(database.SameAs.local_uri == project.local_uri) \
                              .one_or_none()
            
            if same_as:
                log.debug('Sending new issue to remote tracker...')
                
                ticket = pagure_db \
                    .query(model.Ticket) \
                    .filter(model.Ticket.id == issue.id,
                            model.Ticket.project_id == issue.project_id) \
                    .one_or_none()
                
                # Offer a new ticket to the remote tracker
                person.offer(ticket.jsonld, to=same_as.remote_uri)
        
        if topic == 'issue.comment.added':
            # A user has commented on an issue
            
            # The Pagure notification contains *all* the comments of the issue
            # in an ordered list, so we extract the last one from the list of
            # comments.
            comment = pagure_db \
                .query(model.TicketComment) \
                .filter(model.TicketComment.id == message['issue']['comments'][-1]['id']) \
                .one_or_none()
            
            person = pagure_db \
                        .query(model.Person) \
                        .filter(model.Person.id == comment.user.id) \
                        .one_or_none()
            
            project = pagure_db \
                .query(model.Projects) \
                .filter(model.Projects.id == message['project']['id']) \
                .one_or_none()
            
            # Our local ticket
            ticket = pagure_db \
                .query(model.Ticket) \
                .filter(model.Ticket.id == message['issue']['id'],
                        model.Ticket.project_id == message['project']['id']) \
                .one_or_none()
            
            # Check if this tracker is only used to interact with a remote one
            same_as = forgefed_db.query(database.SameAs) \
                              .filter(database.SameAs.local_uri == project.local_uri) \
                              .one_or_none()
            
            if same_as:
                log.debug('Sending new comment to remote tracker...')
                
                assert ticket.remote_uri, 'Ticket not linked to remote ticket.'
                
                # Notify the remote tracker about the new comment
                person.create(comment.jsonld, to=same_as.remote_uri)
            
            else:
                log.debug('Not a remote tracker. Will send new comment to tracker followers '
                    + 'and watchers.')
                
                # Retrieve the pagure "watchlist"
                watchlist = pagure.lib.query.get_watch_list(pagure_db, ticket)
                actors = []
                
                for username in watchlist:
                    actor = pagure_db \
                        .query(model.Person) \
                        .filter(model.Person.user == username) \
                        .one_or_none()
                    
                    actors.append(actor.uri)
                
                # Send the Activity
                person.create(comment.jsonld, to=actors)
        
        if topic == 'issue.edit' \
        and 'status' in message['fields'] \
        and message['issue']['status'].upper() == 'CLOSED':
            # A user has closed an issue
            
            # The Ticket that was modified
            ticket = pagure_db \
                .query(model.Ticket) \
                .filter(model.Ticket.id == message['issue']['id'],
                        model.Ticket.project_id == message['project']['id']) \
                .one_or_none()
            
            # The user that edited the Ticket
            person = pagure_db \
                        .query(model.Person) \
                        .filter(model.Person.user == message['agent']) \
                        .one_or_none()
            
            project = pagure_db \
                .query(model.Projects) \
                .filter(model.Projects.id == message['project']['id']) \
                .one_or_none()
            
            # If the user has edited the Ticket of a remote tracker, we just
            # send the Activity to the tracker
            if ticket.is_remote:
                log.debug('Local user has closed the remote Ticket {}'.format(ticket.uri))
                
                person.resolve(ticket.uri, to=project.remote_uri)
            
            # otherwise we send the Activity to the Tickets' watchlist
            else:
                log.debug('Local user has closed the local Ticket {}'.format(ticket.uri))
                
                # Retrieve the pagure "watchlist"
                watchlist = pagure.lib.query.get_watch_list(pagure_db, ticket)
                actors = []
                
                for username in watchlist:
                    actor = pagure_db \
                        .query(model.Person) \
                        .filter(model.Person.user == username) \
                        .one_or_none()
                    
                    actors.append(actor.uri)
                
                # Send the Activity
                person.resolve(ticket.uri, to=actors)
            








